package com.qfedu.buy.server.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.qfedu.buy.common.config.RabbitMQConstantConfig;
import com.qfedu.buy.common.config.RedisKeyConfig;
import com.qfedu.buy.common.config.SystemConfig;
import com.qfedu.buy.common.dto.UserLoginDto;
import com.qfedu.buy.common.dto.UserOpDto;
import com.qfedu.buy.common.dto.UserTokenDto;
import com.qfedu.buy.common.util.RedissonUtil;
import com.qfedu.buy.common.util.TokenUtil;
import com.qfedu.buy.common.vo.R;
import com.qfedu.buy.server.dao.UserDao;
import com.qfedu.buy.server.dao.UserLogDao;
import com.qfedu.buy.server.entity.User;
import com.qfedu.buy.server.entity.UserLog;
import com.qfedu.buy.server.service.intf.UserService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * @program: NeighborBuy
 * @description:
 * @author: Feri(邢朋辉)
 * @create: 2021-01-25 15:04
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserLogDao logDao;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final String passkey="vkfdjabH8NxFK5RseCIEmg==";
    @Override
    public R checkPhone(String phone) {
        //校验
        if(!StrUtil.isEmptyIfStr(phone)){
            //查询
            User user=userDao.selectByPhone(phone);
            if(user==null){
                //手机号不存在
                return R.ok();
            }
        }
        return R.fail();
    }

    @Override
    public R login(UserLoginDto dto) {
        //多设备唯一登陆  同种设备只要当前账号在线，就不允许二次登陆
        //校验
        if(dto!=null){
            //校验当前账号是否允许登陆
            String phonekey=RedisKeyConfig.USER_PHONE+dto.getPhone()+":"+ dto.getType();
            //Redis记录令牌 和设备
            if(RedissonUtil.isHave(phonekey)){
                //在当前的设备上，本账号已经在线
                //记录操作
                logDao.insert(new UserLog(0, SystemConfig.OAUTH_TYPE_UNIQUE,"在当前的设备上，本账号已经在线",dto.getIp()));
                return R.fail("亲，账号已在线");
            }else{
                //本次登陆允许
                User user=userDao.selectByPhone(dto.getPhone());
                if(user!=null){
                    //密码校验
                    if(user.getPass().equals(SecureUtil.aes(
                            Base64.getDecoder().decode(passkey)).
                            encryptHex(dto.getPass()))){
                        //账号正确
                        //生成令牌
                        String token= TokenUtil.createToken(user.getId());
                        //存储令牌
                        RedissonUtil.setStr(phonekey,token,RedisKeyConfig.USER_TOKEN_TIME);
                        UserTokenDto userTokenDto=new UserTokenDto();
                        userTokenDto.setId(user.getId());
                        userTokenDto.setPhone(dto.getPhone());
                        userTokenDto.setType(dto.getType());
                        RedissonUtil.setStr(RedisKeyConfig.USER_TOKEN+token,userTokenDto,RedisKeyConfig.USER_TOKEN_TIME);
                        //记录日志
                        logDao.insert(new UserLog(user.getId(),SystemConfig.OAUTH_TYPE_LOGIN,"登陆成功",dto.getIp()));
                        //返回结果-令牌
                        return R.ok(token);
                    }else {
                        //账号密码错误
                        logDao.insert(new UserLog(user.getId(),SystemConfig.OAUTH_TYPE_LOGINERROR,"登陆失败",dto.getIp()));
                    }
                }
            }
        }
        return R.fail();
    }

    @Transactional //事务
    @Override
    public R register(UserOpDto dto) {
        if(dto!=null){
            if(userDao.selectByPhone(dto.getPhone())==null){
                User user=new User();
                user.setPhone(dto.getPhone());
                user.setPass(SecureUtil.aes(Base64.getDecoder().decode(passkey)).encryptHex(dto.getPass()));
                userDao.insert(user);
                logDao.insert(new UserLog(user.getId(),SystemConfig.OAUTH_TYPE_ADD,"注册新用户",dto.getIp()));
                //直接修改数据
                //发送RabbitMQ消息 实现用户初始化信息
                rabbitTemplate.convertAndSend("", RabbitMQConstantConfig.QUEUE_USER_INIT,user.getId());
                return R.ok();
            }
        }
        return R.fail();
    }

    @Override
    public R findPass(UserOpDto dto) {
        if(dto!=null){
            User user=userDao.selectByPhone(dto.getPhone());
            if(user!=null){
                userDao.updatePass(user.getId(),SecureUtil.aes(Base64.getDecoder().decode(passkey)).encryptHex(dto.getPass()));
                logDao.insert(new UserLog(user.getId(),SystemConfig.OAUTH_TYPE_FINDPASS,"找回密码，进行了密码重置",dto.getIp()));
                //当前账号的所有在线信息，全部下线
                //删除Redis
                delKeys(user.getPhone());
                return R.ok();
            }
        }
        return R.fail();
    }

    @Override
    public R changePass(String token, String pass, String ip) {
        String json =TokenUtil.getToken(token);
        if(!StrUtil.isEmptyIfStr(json)){
            User user= JSON.parseObject(json,User.class);
            userDao.updatePass(user.getId(),SecureUtil.aes(Base64.getDecoder().decode(passkey)).encryptHex(pass));
            logDao.insert(new UserLog(user.getId(),SystemConfig.OAUTH_TYPE_PASS,"修改了密码",ip));
            //当前账号的所有在线信息，全部下线
            //删除Redis
            delKeys(user.getPhone());
            return R.ok();
        }
        return R.fail();
    }

    private void delKeys(String phone){
        Iterable<String> keys=RedissonUtil.keys(RedisKeyConfig.USER_PHONE+phone+"*");
        List<String> list=new ArrayList<>();
        if(keys!=null){
            for (String key:keys){
                //记录删除令牌
                list.add(RedisKeyConfig.USER_TOKEN+RedissonUtil.getStr(key));
                //记录要删除账号设备信息
                list.add(key);
            }
            RedissonUtil.delKeys(list.toArray(new String[list.size()]));
        }
    }

    @Override
    public R checkToken(String token) {
        if(!StrUtil.isEmptyIfStr(token)){
            if(RedissonUtil.isHave(RedisKeyConfig.USER_TOKEN+token)){
                return R.ok();
            }
        }
        return R.fail();
    }
}
